using System;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using TerritoryGame.Application.Commands;
using TerritoryGame.Application.Dtos;
using TerritoryGame.Domain.Entities.App;
using TerritoryGame.Infrastructure.Data;
using TerritoryGame.Application.Interfaces;
using System.Collections.Concurrent;
using TerritoryGame.Domain.Interfaces;
using TerritoryGame.Domain.DomainEvents;
using BCrypt.Net;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Collections.Generic; // Added for List

namespace TerritoryGame.Application.Services;

public class AppAuthService : IAppAuthService
{
    private readonly TerritoryGameDbContext _db;
    private readonly IAppTokenService _tokenService;
    private readonly IDomainEventPublisher _eventPublisher;
    
    // 简单的内存缓存，存储用户的 token
    private static readonly ConcurrentDictionary<string, (string AccessToken, string RefreshToken, DateTime CreatedAt)> _tokenCache = new();
    
    public AppAuthService(TerritoryGameDbContext db, IAppTokenService tokenService, IDomainEventPublisher eventPublisher)
    {
        _db = db;
        _tokenService = tokenService;
        _eventPublisher = eventPublisher;
    }
    
    public async Task<ApiResult> RegisterAsync(UserRegisterDto dto)
    {
        try
        {
            // 验证输入
            if (string.IsNullOrEmpty(dto.Username))
                return ApiResult.Failed((int)ApiStatusCode.BAD_REQUEST, "用户名不能为空");
            if (string.IsNullOrEmpty(dto.Password))
                return ApiResult.Failed((int)ApiStatusCode.BAD_REQUEST, "密码不能为空");
            if (string.IsNullOrEmpty(dto.Email))
                return ApiResult.Failed((int)ApiStatusCode.BAD_REQUEST, "邮箱不能为空");

            // 检查用户名是否已存在
            var existingUsername = await _db.Users.FirstOrDefaultAsync(u => u.Username == dto.Username);
            if (existingUsername != null)
                return ApiResult.Failed((int)ApiStatusCode.CONFLICT, "用户名已存在");

            // 检查邮箱是否已存在
            var existingEmail = await _db.Users.FirstOrDefaultAsync(u => u.Email == dto.Email);
            if (existingEmail != null)
                return ApiResult.Failed((int)ApiStatusCode.CONFLICT, "该邮箱已被注册");

            // 检查手机号是否已存在（如果提供了手机号）
            if (!string.IsNullOrEmpty(dto.Phone))
            {
                var existingPhone = await _db.Users.FirstOrDefaultAsync(u => u.Phone == dto.Phone);
                if (existingPhone != null)
                    return ApiResult.Failed((int)ApiStatusCode.CONFLICT, "该手机号已被注册");
            }

            // 生成盐值和密码哈希
            var salt = BCrypt.Net.BCrypt.GenerateSalt();
            var hashedPassword = HashPassword(dto.Password, salt);

            // 创建新用户
            var user = new User
            {
                Username = dto.Username,
                Password = hashedPassword,
                Salt = salt,
                Email = dto.Email,
                // 后端兜底：数据库将 phone 定义为非空列，前端注册可不填，这里统一存空字符串避免 NULL 违规
                Phone = dto.Phone ?? string.Empty,
                Avatar = "default-avatar.png", // 设置默认头像
                CreatedAt = DateTime.UtcNow,
                UpdatedAt = DateTime.UtcNow,
                IsActive = true,
                IsDeleted = false
            };

            // 保存用户（单独捕获，便于定位问题）
            try
            {
                _db.Users.Add(user);
                await _db.SaveChangesAsync();
            }
            catch (Exception saveUserEx)
            {
                var inner = saveUserEx.InnerException?.Message ?? "";
                return ApiResult.Failed((int)ApiStatusCode.INTERNAL_ERROR, $"保存用户失败: {saveUserEx.Message} {inner}");
            }

            // 发布用户注册事件
            // 防御性：立即创建默认等级记录（与领域事件并行，确保一定存在）
            var hasLevel = await _db.UserLevels.AnyAsync(ul => ul.UserId == user.Id);
            if (!hasLevel)
            {
                var level = new UserLevel
                {
                    Id = Guid.NewGuid(),
                    UserId = user.Id,
                    CurrentLevel = 1,
                    CurrentExperience = 0,
                    TotalExperience = 0,
                    CurrentTitle = "墨痕初绽",
                    UnlockedTitles = new List<string> { "墨痕初绽" },
                    LastLevelUpTime = DateTime.UtcNow,
                    IsActive = true,
                    IsDeleted = false,
                    CreatedAt = DateTime.UtcNow,
                    UpdatedAt = DateTime.UtcNow
                };
                try
                {
                    _db.UserLevels.Add(level);
                    await _db.SaveChangesAsync();
                }
                catch (Exception saveLevelEx)
                {
                    var inner = saveLevelEx.InnerException?.Message ?? "";
                    return ApiResult.Failed((int)ApiStatusCode.INTERNAL_ERROR, $"创建默认等级失败: {saveLevelEx.Message} {inner}");
                }
            }

            // 发布用户注册事件（用于日志与潜在扩展）
            var userRegisteredEvent = new UserRegisteredEvent(user, "web");
            await _eventPublisher.PublishAsync(userRegisteredEvent);

            return ApiResult.Success("注册成功");
        }
        catch (Exception ex)
        {
            var inner = ex.InnerException?.Message ?? "";
            return ApiResult.Failed((int)ApiStatusCode.INTERNAL_ERROR, $"注册过程中发生错误: {ex.Message} {inner}");
        }
    }
    
    public async Task<ApiResult> LoginAsync(UserLoginDto dto)
    {
        try
        {
            Console.WriteLine($"LoginAsync: 开始处理登录请求 - 用户名: {dto.Username}");

            // 输入验证
            if (string.IsNullOrWhiteSpace(dto.Username))
                return ApiResult.Failed((int)ApiStatusCode.BAD_REQUEST, "用户名不能为空");
            if (string.IsNullOrWhiteSpace(dto.Password))
                return ApiResult.Failed((int)ApiStatusCode.BAD_REQUEST, "密码不能为空");

            // 查找用户
            var user = await _db.Users
                .FirstOrDefaultAsync(u => u.Username == dto.Username);
            
            if (user == null)
            {
                Console.WriteLine($"LoginAsync: 用户不存在 - {dto.Username}");
                await _eventPublisher.PublishAsync(new UserLoginFailedEvent(dto.Username, "用户不存在", "127.0.0.1", 1));
                return ApiResult.Failed((int)ApiStatusCode.UNAUTHORIZED, "用户名或密码错误");
            }

            Console.WriteLine($"LoginAsync: 找到用户 - {user.Username}");

            // 检查用户状态
            if (!user.IsActive)
            {
                Console.WriteLine($"LoginAsync: 账号已被禁用 - {user.Username}");
                await _eventPublisher.PublishAsync(new UserLoginFailedEvent(dto.Username, "账号已被禁用", "127.0.0.1", 1));
                return ApiResult.Failed((int)ApiStatusCode.FORBIDDEN, "账号已被禁用，无法登录");
            }

            // 验证密码
            var hashedPassword = HashPassword(dto.Password, user.Salt);
            if (user.Password != hashedPassword)
            {
                Console.WriteLine($"LoginAsync: 密码错误 - {user.Username}");
                await _eventPublisher.PublishAsync(new UserLoginFailedEvent(dto.Username, "密码错误", "127.0.0.1", 1));
                return ApiResult.Failed((int)ApiStatusCode.UNAUTHORIZED, "用户名或密码错误");
            }

            Console.WriteLine($"LoginAsync: 密码验证成功 - {user.Username}");

            // 登录成功
            user.LastLoginTime = DateTime.UtcNow;

            // 生成令牌 - 使用重写的逻辑
            Console.WriteLine($"LoginAsync: 开始生成令牌 - {user.Username}");
            var tokenResult = await GenerateLoginTokensAsync(user);
            
            if (tokenResult.Code != (int)ApiStatusCode.SUCCESS)
            {
                Console.WriteLine($"LoginAsync: 令牌生成失败 - {tokenResult.Message}");
                return tokenResult;
            }

            await _db.SaveChangesAsync();

            // 发布登录成功事件
            await _eventPublisher.PublishAsync(new UserLoggedInEvent(user, "web", "127.0.0.1"));

            Console.WriteLine($"LoginAsync: 登录成功 - {user.Username}");
            return tokenResult;
        }
        catch (Exception ex)
        {
            Console.WriteLine($"LoginAsync: 登录过程中发生错误 - {ex.Message}");
            Console.WriteLine($"LoginAsync: 异常堆栈 - {ex.StackTrace}");
            return ApiResult.Failed((int)ApiStatusCode.INTERNAL_ERROR, $"登录过程中发生错误: {ex.Message}");
        }
    }

    /// <summary>
    /// 生成登录令牌 - 重写的核心逻辑
    /// </summary>
    private Task<ApiResult> GenerateLoginTokensAsync(User user)
    {
        try
        {
            Console.WriteLine($"GenerateLoginTokensAsync: 开始为用户 {user.Username} 生成令牌");

            // 使用AppTokenService生成令牌
            var (accessToken, refreshToken) = _tokenService.GenerateTokens(user);
            
            Console.WriteLine($"GenerateLoginTokensAsync: 令牌生成完成");
            Console.WriteLine($"  AccessToken长度: {accessToken?.Length ?? 0}");
            Console.WriteLine($"  RefreshToken长度: {refreshToken?.Length ?? 0}");

            // 验证生成的令牌
            if (string.IsNullOrEmpty(accessToken) || string.IsNullOrEmpty(refreshToken))
            {
                Console.WriteLine($"GenerateLoginTokensAsync: 令牌生成失败 - 令牌为空");
                return Task.FromResult(ApiResult.Failed((int)ApiStatusCode.INTERNAL_ERROR, "令牌生成失败"));
            }

            // 验证令牌格式
            if (!accessToken.StartsWith("eyJ") || !refreshToken.StartsWith("eyJ"))
            {
                Console.WriteLine($"GenerateLoginTokensAsync: 令牌格式错误");
                return Task.FromResult(ApiResult.Failed((int)ApiStatusCode.INTERNAL_ERROR, "令牌格式错误"));
            }

            // 简单验证令牌格式
            if (!accessToken.StartsWith("eyJ") || !refreshToken.StartsWith("eyJ"))
            {
                Console.WriteLine($"GenerateLoginTokensAsync: 令牌格式错误");
                return Task.FromResult(ApiResult.Failed((int)ApiStatusCode.INTERNAL_ERROR, "令牌格式错误"));
            }

            Console.WriteLine($"GenerateLoginTokensAsync: 令牌格式验证成功");

            // 构建用户信息
            var userInfo = new
            {
                id = user.Id.ToString(),
                username = user.Username,
                email = user.Email,
                phone = user.Phone,
                avatar = user.Avatar,
                lastLoginTime = user.LastLoginTime
            };

            // 构建返回结果
            var loginResult = new
            {
                accessToken = accessToken,
                refreshToken = refreshToken,
                user = userInfo,
                expiresIn = 120 * 60, // 2小时，以秒为单位
                tokenType = "Bearer"
            };

            Console.WriteLine($"GenerateLoginTokensAsync: 登录令牌生成成功 - {user.Username}");
            return Task.FromResult(ApiResult.Success("登录成功", loginResult));
        }
        catch (Exception ex)
        {
            Console.WriteLine($"GenerateLoginTokensAsync: 令牌生成过程中发生错误 - {ex.Message}");
            return Task.FromResult(ApiResult.Failed((int)ApiStatusCode.INTERNAL_ERROR, $"令牌生成失败: {ex.Message}"));
        }
    }


    
    public Task<ApiResult> RefreshTokenAsync(string refreshToken, bool forceRefresh = false)
    {
        if (string.IsNullOrWhiteSpace(refreshToken))
        {
            return Task.FromResult(ApiResult.Failed((int)ApiStatusCode.BAD_REQUEST, "刷新令牌不能为空"));
        }
        
        var newAccessToken = _tokenService.RefreshAccessToken(refreshToken);
        if (newAccessToken == null)
        {
            return Task.FromResult(ApiResult.Failed((int)ApiStatusCode.UNAUTHORIZED, "刷新Token失败，请重新登录"));
        }
        
        return Task.FromResult(ApiResult.Success("Token刷新成功", new { accessToken = newAccessToken }));
    }

    /// <summary>
    /// 智能刷新 Token
    /// </summary>
    public async Task<ApiResult> SmartRefreshTokenAsync(string refreshToken, bool forceRefresh = false)
    {
        try
        {
            // 输入验证
            if (string.IsNullOrWhiteSpace(refreshToken))
            {
                return ApiResult.Failed((int)ApiStatusCode.BAD_REQUEST, "刷新令牌不能为空");
            }

            // 清理令牌
            refreshToken = refreshToken.Trim();

            // 验证令牌格式
            if (!refreshToken.StartsWith("eyJ"))
            {
                return ApiResult.Failed((int)ApiStatusCode.BAD_REQUEST, "刷新令牌格式错误");
            }

            // 使用AppTokenService刷新访问令牌
            var newAccessToken = _tokenService.RefreshAccessToken(refreshToken);
            
            if (string.IsNullOrEmpty(newAccessToken))
            {
                return ApiResult.Failed((int)ApiStatusCode.UNAUTHORIZED, "刷新令牌无效或已过期");
            }

            // 解析刷新令牌获取用户信息
            var handler = new System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler();
            var token = handler.ReadJwtToken(refreshToken);
            
            // 使用多种claim类型查找用户ID，优先使用sub
            var userIdClaim = token.Claims.FirstOrDefault(c => c.Type == "sub")?.Value
                ?? token.Claims.FirstOrDefault(c => c.Type == "user_id")?.Value
                ?? token.Claims.FirstOrDefault(c => c.Type == "uid")?.Value
                ?? token.Claims.FirstOrDefault(c => c.Type == System.Security.Claims.ClaimTypes.NameIdentifier)?.Value;
            
            if (string.IsNullOrEmpty(userIdClaim))
            {
                return ApiResult.Failed((int)ApiStatusCode.UNAUTHORIZED, "刷新令牌缺少必要的用户信息");
            }

            // 验证用户是否存在且状态正常
            var userId = Guid.Parse(userIdClaim);
            var user = await _db.Users.FirstOrDefaultAsync(u => u.Id == userId);
            
            if (user == null)
            {
                return ApiResult.Failed((int)ApiStatusCode.NOT_FOUND, "用户不存在");
            }
            
            // 检查用户状态
            if (!user.IsActive)
            {
                return ApiResult.Failed((int)ApiStatusCode.FORBIDDEN, "用户账号状态异常，无法刷新令牌");
            }
            
            // 更新用户最后活动时间
            user.LastActivityTime = DateTime.UtcNow;
            await _db.SaveChangesAsync();

            // 构建返回结果
            var refreshResult = new
            {
                accessToken = newAccessToken,
                expiresIn = 120 * 60, // 120分钟，单位：秒
                tokenType = "Bearer",
                refreshToken = refreshToken // 返回原刷新令牌
            };

            return ApiResult.Success("令牌刷新成功", refreshResult);
        }
        catch (Exception ex)
        {
            Console.WriteLine($"SmartRefreshTokenAsync: 刷新令牌时发生错误 - {ex.Message}");
            return ApiResult.Failed((int)ApiStatusCode.INTERNAL_ERROR, "刷新令牌时发生错误");
        }
    }

    public async Task<ApiResult> ValidateUserInfoAsync(ValidateUserInfoDto dto)
    {
        try
        {
            Console.WriteLine($"ValidateUserInfoAsync: 开始验证用户信息");
            Console.WriteLine($"ValidateUserInfoAsync: Email: '{dto.Email}', Phone: '{dto.Phone}'");
            
            // 输入验证
            if (string.IsNullOrEmpty(dto.Email))
                return ApiResult.Failed((int)ApiStatusCode.BAD_REQUEST, "邮箱不能为空");

            if (string.IsNullOrEmpty(dto.Phone))
                return ApiResult.Failed((int)ApiStatusCode.BAD_REQUEST, "手机号不能为空");

            // 检查邮箱格式
            if (!System.Text.RegularExpressions.Regex.IsMatch(dto.Email, @"^[^@\s]+@[^@\s]+\.[^@\s]+$"))
                return ApiResult.Failed((int)ApiStatusCode.BAD_REQUEST, "邮箱格式不正确");
            
            // 检查手机号格式
            if (!System.Text.RegularExpressions.Regex.IsMatch(dto.Phone, @"^1[3-9]\d{9}$"))
                return ApiResult.Failed((int)ApiStatusCode.BAD_REQUEST, "手机号格式不正确");

            Console.WriteLine($"ValidateUserInfoAsync: 开始查找用户 - Email: {dto.Email}, Phone: {dto.Phone}");
            
            // 先分别检查邮箱和手机号是否存在
            var userByEmail = await _db.Users.FirstOrDefaultAsync(u => u.Email == dto.Email);
            var userByPhone = await _db.Users.FirstOrDefaultAsync(u => u.Phone == dto.Phone);
            
            // 检查邮箱是否存在
            if (userByEmail == null)
            {
                Console.WriteLine($"ValidateUserInfoAsync: 邮箱不存在 - Email: {dto.Email}");
                return ApiResult.Failed((int)ApiStatusCode.NOT_FOUND, "邮箱地址不正确，请确认邮箱地址是否正确");
            }
            
            // 检查手机号是否存在
            if (userByPhone == null)
            {
                Console.WriteLine($"ValidateUserInfoAsync: 手机号不存在 - Phone: {dto.Phone}");
                return ApiResult.Failed((int)ApiStatusCode.NOT_FOUND, "手机号不正确，请确认手机号是否正确");
            }
            
            // 检查邮箱和手机号是否属于同一个用户
            if (userByEmail.Id != userByPhone.Id)
            {
                Console.WriteLine($"ValidateUserInfoAsync: 邮箱和手机号不匹配 - Email: {dto.Email}, Phone: {dto.Phone}");
                return ApiResult.Failed((int)ApiStatusCode.BAD_REQUEST, "邮箱和手机号不匹配，请确认输入的信息是否正确");
            }

            // 检查用户状态
            if (!userByEmail.IsActive)
            {
                Console.WriteLine($"ValidateUserInfoAsync: 用户账号状态异常 - IsActive: {userByEmail.IsActive}");
                return ApiResult.Failed((int)ApiStatusCode.FORBIDDEN, "用户账号状态异常，无法进行密码重置");
            }

            Console.WriteLine($"ValidateUserInfoAsync: 用户信息验证成功 - ID: {userByEmail.Id}, Username: {userByEmail.Username}");

            // 返回验证成功的结果，但不包含敏感信息
            var validationResult = new
            {
                isValid = true,
                message = "用户信息验证成功，可以进行密码重置",
                userId = userByEmail.Id.ToString(),
                username = userByEmail.Username,
                email = userByEmail.Email,
                phone = userByEmail.Phone
            };

            return ApiResult.Success("用户信息验证成功", validationResult);
        }
        catch (Exception ex)
        {
            Console.WriteLine($"ValidateUserInfoAsync: 发生异常 - {ex.Message}");
            Console.WriteLine($"ValidateUserInfoAsync: 异常堆栈 - {ex.StackTrace}");
            return ApiResult.Failed((int)ApiStatusCode.INTERNAL_ERROR, $"验证用户信息时发生错误: {ex.Message}");
        }
    }

    public async Task<ApiResult> ForgetPasswordAsync(ForgetPasswordDto dto)
    {
        try
        {
            Console.WriteLine($"ForgetPasswordAsync: 开始处理忘记密码请求");
            Console.WriteLine($"ForgetPasswordAsync: Email: '{dto.Email}', Phone: '{dto.Phone}'");
            
            // 验证输入
            if (string.IsNullOrEmpty(dto.Email))
                return ApiResult.Failed((int)ApiStatusCode.BAD_REQUEST, "邮箱不能为空");

            if (string.IsNullOrEmpty(dto.Phone))
                return ApiResult.Failed((int)ApiStatusCode.BAD_REQUEST, "手机号不能为空");

            if (string.IsNullOrEmpty(dto.NewPassword))
                return ApiResult.Failed((int)ApiStatusCode.BAD_REQUEST, "新密码不能为空");

            if (dto.NewPassword != dto.ConfirmPassword)
                return ApiResult.Failed((int)ApiStatusCode.BAD_REQUEST, "两次输入的密码不一致");

            // 检查邮箱格式
            if (!System.Text.RegularExpressions.Regex.IsMatch(dto.Email, @"^[^@\s]+@[^@\s]+\.[^@\s]+$"))
                return ApiResult.Failed((int)ApiStatusCode.BAD_REQUEST, "邮箱格式不正确");
            
            // 检查手机号格式
            if (!System.Text.RegularExpressions.Regex.IsMatch(dto.Phone, @"^1[3-9]\d{9}$"))
                return ApiResult.Failed((int)ApiStatusCode.BAD_REQUEST, "手机号格式不正确");

            Console.WriteLine($"ForgetPasswordAsync: 开始查找用户 - Email: {dto.Email}, Phone: {dto.Phone}");
            
            // 先分别检查邮箱和手机号是否存在
            var userByEmail = await _db.Users.FirstOrDefaultAsync(u => u.Email == dto.Email);
            var userByPhone = await _db.Users.FirstOrDefaultAsync(u => u.Phone == dto.Phone);
            
            // 检查邮箱是否存在
            if (userByEmail == null)
            {
                Console.WriteLine($"ForgetPasswordAsync: 邮箱不存在 - Email: {dto.Email}");
                return ApiResult.Failed((int)ApiStatusCode.NOT_FOUND, "邮箱地址不正确，请确认邮箱地址是否正确");
            }
            
            // 检查手机号是否存在
            if (userByPhone == null)
            {
                Console.WriteLine($"ForgetPasswordAsync: 手机号不存在 - Phone: {dto.Phone}");
                return ApiResult.Failed((int)ApiStatusCode.NOT_FOUND, "手机号不正确，请确认手机号是否正确");
            }
            
            // 检查邮箱和手机号是否属于同一个用户
            if (userByEmail.Id != userByPhone.Id)
            {
                Console.WriteLine($"ForgetPasswordAsync: 邮箱和手机号不匹配 - Email: {dto.Email}, Phone: {dto.Phone}");
                return ApiResult.Failed((int)ApiStatusCode.BAD_REQUEST, "邮箱和手机号不匹配，请确认输入的信息是否正确");
            }
            
            // 使用邮箱查找用户（因为已经确认邮箱存在）
            var user = userByEmail;

            Console.WriteLine($"ForgetPasswordAsync: 找到用户 - ID: {user.Id}, Username: {user.Username}");

            // 检查用户状态
            if (!user.IsActive)
            {
                Console.WriteLine($"ForgetPasswordAsync: 用户账号状态异常 - IsActive: {user.IsActive}");
                return ApiResult.Failed((int)ApiStatusCode.FORBIDDEN, "用户账号状态异常，无法修改密码");
            }

            // 更新用户密码
            Console.WriteLine($"ForgetPasswordAsync: 开始更新用户密码");
            var salt = BCrypt.Net.BCrypt.GenerateSalt();
            var hashedPassword = HashPassword(dto.NewPassword, salt);

            user.Password = hashedPassword;
            user.Salt = salt;
            user.UpdatedAt = DateTime.UtcNow;

            await _db.SaveChangesAsync();
            Console.WriteLine($"ForgetPasswordAsync: 密码更新成功");

            // 发布密码重置事件
            var passwordResetEvent = new UserPasswordResetEvent(user);
            await _eventPublisher.PublishAsync(passwordResetEvent);

            return ApiResult.Success("密码重置成功，请使用新密码登录");
        }
        catch (Exception ex)
        {
            Console.WriteLine($"ForgetPasswordAsync: 发生异常 - {ex.Message}");
            Console.WriteLine($"ForgetPasswordAsync: 异常堆栈 - {ex.StackTrace}");
            return ApiResult.Failed((int)ApiStatusCode.INTERNAL_ERROR, $"忘记密码处理时发生错误: {ex.Message}");
        }
    }
    
    private static string HashPassword(string password, string salt)
    {
        byte[] bytes = Encoding.UTF8.GetBytes(password + salt);
        byte[] hash = SHA256.HashData(bytes);
        return Convert.ToBase64String(hash);
    }

    private string GenerateRandomCode(int length)
    {
        const string chars = "0123456789";
        var random = new Random();
        return new string(Enumerable.Repeat(chars, length)
            .Select(s => s[random.Next(s.Length)]).ToArray());
    }


}